import time
import pandas as pd


def get_now_time():
    return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())


def save_log(s):
    with open("./logs/log.txt", "a") as f:
        f.write(s)


def pack_metric_fun(*funes, **name_funes):
    res = dict()
    for fun in funes:
        res[fun.__name__] = fun

    for name in name_funes:
        res[name] = name_funes[name]

    return res


def _to_df(vals):
    return pd.DataFrame(vals)


class Log:
    """
    Log 基类
    """

    def __init__(self, save):
        self.st = get_now_time()
        self.et = None
        self.save = save

    def _log_time(self):
        s = "日志开始时间:" + self.st + "\n"
        return s

    def _print(self, s_head, s_body):
        s = ""
        s += s_head + s_body

        s += "日志结束时间:" + self.et + "\n"
        if self.save:
            save_log(s)
        return s

    def __call__(self, fun):
        def wrapper(y_true, y_pred):
            val = fun(y_true, y_pred)
            self.et = get_now_time()
            s_head = self._log_time()
            s_body = ""
            for it in val:
                s_body += "metric:{:8s}\tvalues:{:.4f}\n".format(it, val[it])
            s = self._print(s_head, s_body)
            print(s)
            return val

        return wrapper


def _print(s_head, s_body, s_tail):
    s = ""
    s += s_head + s_body + s_tail

    save_log(s)
    return s


class MatrixLog:
    def __init__(self, *funes, **name_funes):
        self.funes = funes
        self.name_funes = name_funes
        self.vals = {"metrics": [], "values": []}
        self.st = get_now_time()
        self.et = None
        self.count = 0

    def _reset(self):
        self.vals = {"metrics": [], "values": []}
        self.st = get_now_time()
        self.et = None
        self.count = 0

    def to_df(self):
        return _to_df(self.vals)

    def _log_time(self, st=True):
        if st:
            s = "日志开始时间:" + self.st + "\n"
        else:
            s = "日志结束时间:" + self.et + "\n"
        return s

    def to_markdown(self):
        return _to_df(self.vals).to_markdown()

    def __str__(self):
        s = ""
        s += "{:^40s}\t{:^8s}\n".format("MetricNames", "Values")
        for i in range(self.count):
            s += "{:40s}\t{:4.4f}\n".format(self.vals['metrics'][i], self.vals['values'][i])
        return s

    def __call__(self, y_true, y_pred, is_print=False):
        self._reset()
        funes = pack_metric_fun(*self.funes, **self.name_funes)

        for fun in funes:
            self.vals['metrics'].append(fun)
            self.vals['values'].append(funes[fun](y_true, y_pred))
            self.count += 1

        if is_print:
            self.et = get_now_time()
            s_head = self._log_time()
            s_body = self.__str__()
            s_tail = self._log_time(False)
            s = _print(s_head, s_body, s_tail)

            print(s)

        return self.vals
